package com.linden.std.service.auth.impl;

import com.linden.std.service.auth.LoginSecurityService;
import com.linden.std.util.RedisTemplateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 登录安全控制服务实现
 * 基于Redis实现登录防暴力破解机制
 */
@Slf4j
@Service
public class LoginSecurityServiceImpl implements LoginSecurityService {
    
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;
    
    // 账户登录失败次数限制（默认5次）
    @Value("${std.security.login.max-attempts:5}")
    private int maxAttempts;
    
    // 账户锁定时间（秒，默认30分钟）
    @Value("${std.security.login.account-lock-time:1800}")
    private long accountLockTime;
    
    // IP登录失败次数限制（默认10次）
    @Value("${std.security.login.ip-max-attempts:10}")
    private int ipMaxAttempts;
    
    // IP锁定时间（秒，默认1小时）
    @Value("${std.security.login.ip-lock-time:3600}")
    private long ipLockTime;
    
    // 失败记录过期时间（秒，默认1小时）
    @Value("${std.security.login.failure-expire-time:3600}")
    private long failureExpireTime;
    
    // Redis键前缀
    private static final String ACCOUNT_FAILURE_PREFIX = "login:failure:account:";
    private static final String ACCOUNT_LOCK_PREFIX = "login:lock:account:";
    private static final String IP_FAILURE_PREFIX = "login:failure:ip:";
    private static final String IP_LOCK_PREFIX = "login:lock:ip:";
    
    @Override
    public boolean isAccountLocked(String account) {
        String lockKey = ACCOUNT_LOCK_PREFIX + account;
        String lockValue = redisTemplateUtil.get(lockKey);
        
        if (lockValue != null) {
            log.warn("账户 {} 当前被锁定", account);
            return true;
        }
        
        return false;
    }
    
    @Override
    public boolean isIpLocked(String ip) {
        String lockKey = IP_LOCK_PREFIX + ip;
        String lockValue = redisTemplateUtil.get(lockKey);
        
        if (lockValue != null) {
            log.warn("IP {} 当前被锁定", ip);
            return true;
        }
        
        return false;
    }
    
    @Override
    public void recordLoginFailure(String account, String ip) {
        // 记录账户失败次数
        recordAccountFailure(account);
        
        // 记录IP失败次数
        recordIpFailure(ip);
        
        log.warn("记录登录失败 - 账户: {}, IP: {}", account, ip);
    }
    
    @Override
    public void clearLoginFailures(String account, String ip) {
        // 清除账户失败记录
        String accountFailureKey = ACCOUNT_FAILURE_PREFIX + account;
        redisTemplateUtil.delete(accountFailureKey);
        
        // 清除IP失败记录
        String ipFailureKey = IP_FAILURE_PREFIX + ip;
        redisTemplateUtil.delete(ipFailureKey);
        
        log.info("清除登录失败记录 - 账户: {}, IP: {}", account, ip);
    }
    
    @Override
    public int getRemainingAttempts(String account) {
        String failureKey = ACCOUNT_FAILURE_PREFIX + account;
        String failureCountStr = redisTemplateUtil.get(failureKey);
        
        int currentFailures = 0;
        if (failureCountStr != null) {
            try {
                currentFailures = Integer.parseInt(failureCountStr);
            } catch (NumberFormatException e) {
                log.warn("解析失败次数异常: {}", e.getMessage());
            }
        }
        
        return Math.max(0, maxAttempts - currentFailures);
    }
    
    @Override
    public long getAccountLockRemainingTime(String account) {
        String lockKey = ACCOUNT_LOCK_PREFIX + account;
        Long ttl = redisTemplateUtil.getExpire(lockKey);
        
        return ttl != null && ttl > 0 ? ttl : -1;
    }
    
    @Override
    public long getIpLockRemainingTime(String ip) {
        String lockKey = IP_LOCK_PREFIX + ip;
        Long ttl = redisTemplateUtil.getExpire(lockKey);
        
        return ttl != null && ttl > 0 ? ttl : -1;
    }
    
    /**
     * 记录账户登录失败
     */
    private void recordAccountFailure(String account) {
        String failureKey = ACCOUNT_FAILURE_PREFIX + account;
        String failureCountStr = redisTemplateUtil.get(failureKey);
        
        int failureCount = 0;
        if (failureCountStr != null) {
            try {
                failureCount = Integer.parseInt(failureCountStr);
            } catch (NumberFormatException e) {
                log.warn("解析账户失败次数异常: {}", e.getMessage());
            }
        }
        
        failureCount++;
        
        // 更新失败次数
        redisTemplateUtil.set(failureKey, String.valueOf(failureCount), failureExpireTime);
        
        // 检查是否需要锁定账户
        if (failureCount >= maxAttempts) {
            String lockKey = ACCOUNT_LOCK_PREFIX + account;
            redisTemplateUtil.set(lockKey, String.valueOf(System.currentTimeMillis()), accountLockTime);
            
            log.warn("账户 {} 登录失败次数达到 {} 次，锁定 {} 秒", account, failureCount, accountLockTime);
        } else {
            log.warn("账户 {} 登录失败 {} 次，剩余尝试次数: {}", account, failureCount, maxAttempts - failureCount);
        }
    }
    
    /**
     * 记录IP登录失败
     */
    private void recordIpFailure(String ip) {
        String failureKey = IP_FAILURE_PREFIX + ip;
        String failureCountStr = redisTemplateUtil.get(failureKey);
        
        int failureCount = 0;
        if (failureCountStr != null) {
            try {
                failureCount = Integer.parseInt(failureCountStr);
            } catch (NumberFormatException e) {
                log.warn("解析IP失败次数异常: {}", e.getMessage());
            }
        }
        
        failureCount++;
        
        // 更新失败次数
        redisTemplateUtil.set(failureKey, String.valueOf(failureCount), failureExpireTime);
        
        // 检查是否需要锁定IP
        if (failureCount >= ipMaxAttempts) {
            String lockKey = IP_LOCK_PREFIX + ip;
            redisTemplateUtil.set(lockKey, String.valueOf(System.currentTimeMillis()), ipLockTime);
            
            log.warn("IP {} 登录失败次数达到 {} 次，锁定 {} 秒", ip, failureCount, ipLockTime);
        } else {
            log.warn("IP {} 登录失败 {} 次，剩余尝试次数: {}", ip, failureCount, ipMaxAttempts - failureCount);
        }
    }
}